/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/10 12:38
  *
  * @file       hd_oled_protocol_spi.c
  * @brief      OLED SPI Communication Protocol Hardware Driver.
  *
  * @note       This file contains the SPI Communication Protocol hardware
  *             driver for the OLED.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date           Author       Notes
  *   2024-06-10     Chris        the first version
  *
  ******************************************************************************
  */

#include "hd_oled_protocol_spi.h"
#include <delay.h>


static void OLEDProtocolSPI_init_(const OLEDProtocol *super) {
    const OLEDProtocolSPI *this = (OLEDProtocolSPI *)super;

    GPIO_init(this->dc);
    GPIO_init(this->cs);

    // OLED need a power on reset
    if (this->res) {
        GPIO_init(this->res);
        GPIO_reset(this->res);
        delay_ms(100);
        GPIO_set(this->res);
    }

    SPI_stop(this->spi, this->cs);
}

static void OLEDProtocolSPI_write_(const OLEDProtocol *super,
                                   uint8_t nc, uint16_t datOrCmd, uint8_t *dat, uint8_t len) {
    const OLEDProtocolSPI *this = (OLEDProtocolSPI *)super;

    // Set data or command
    if (datOrCmd == 0) GPIO_reset(this->dc);
    else GPIO_set(this->dc);


    SPI_start(this->spi, this->cs);

    while (len--) {
        SPI_swapByte(this->spi, *dat++);
    }

    SPI_stop(this->spi, this->cs);
}

void OLEDProtocolSPI_constructor(OLEDProtocolSPI *this, SPI *spi, GPIO *res, GPIO *dc, GPIO *cs) {
    static struct OLEDProtocolVtbl vtbl = {
        .init = &OLEDProtocolSPI_init_,
        .write = &OLEDProtocolSPI_write_,
    };

    this->oledProtocol.vptr = &vtbl;

    this->spi = spi;
    this->res = res;
    this->dc = dc;
    this->cs = cs;
}
